<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>日志查询</title>
    <link rel="icon" href="favicon.ico" type="image/png">

    <script src="webjars/lxboot3/js/vue.js"></script>
    <!-- 接口调用-->
    <script src="webjars/lxboot3/js/axios.min.js"></script>
    <script src="webjars/lxboot3/js/clipboard.min.js"></script>
    <!-- 引入组件库 -->
    <script src="webjars/lxboot3/js/element-ui.js"></script>
    <script src="webjars/lxboot3/js/lx.js"></script>
    <!-- 引入样式 -->
    <link rel="stylesheet" href="webjars/lxboot3/js/element-ui.css">
    <link rel="stylesheet" href="webjars/lxboot3/js/element-ui-display.css">

    <!-- 引入组件库 -->
    <script src="webjars/lxboot3/js/prism.js"></script>
    <!-- 引入样式 -->
    <link rel="stylesheet" href="webjars/lxboot3/js/prism.css">
</head>
<body>
<div id="app">
    <el-form :inline="true" :model="from" class="demo-form-inline" ref="from" label-width="100px">
        <el-select placeholder="日志等级" style="width:8%" v-model="from.logLevel" clearable @change="onSubmit">
            <el-option value="" key="ALL">所有</el-option>
            <el-option value="INFO" key="INFO">INFO</el-option>
            <el-option value="ERROR" key="ERROR">ERROR</el-option>
            <el-option value="WARN" key="WARN">WARN</el-option>
            <el-option value="DEBUG" key="DEBUG">DEBUG</el-option>
        </el-select>
        <el-input style="width:8%" v-model="from.firmId" placeholder="企业ID" clearable @change="onSubmit"></el-input>
        <el-input style="width:8%" v-model="from.serverName" placeholder="服务器地址" clearable @change="onSubmit"></el-input>
        <el-input style="width:8%"  v-model="from.appName" placeholder="服务名称" clearable @change="onSubmit"></el-input>
        <el-input style="width:8%"  v-model="from.traceId" placeholder="追踪码" clearable @change="onSubmit"></el-input>
        <el-date-picker style="width:23%" :default-time="['00:00:00', '23:59:59']" @change="onSubmit" v-model="dateTimeRange" type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :clearable="false"></el-date-picker>
        <el-input style="width:15%"  v-model="searchKey" placeholder="搜索条件" @change="onSubmit" clearable ></el-input>
        <el-form-item>
            <el-button  type="primary" @click="get">查询</el-button>
            <el-button  type="primary" @click="onClean">重置</el-button>
        </el-form-item>
    </el-form>

    <el-row style="white-space:nowrap; text-align: center;" :gutter="24">
        <el-col :span="1" class="hidden-md-and-down"><p>
            <el-button type="primary" size="mini"  @click="copy(toSql())">复制</el-button>
            <!--                <el-button type="danger"  size="mini" @click="clearCheckBox" >清空</el-button>-->
        </p></el-col>
        <el-col :span="2" >
            <p>日志时间</p>
        </el-col>
        <el-col :span="2"><p>服务名称</p></el-col>
        <el-col :span="2"><p>日志追踪</p></el-col>
        <p style="white-space:nowrap;text-align: left; padding-left: 2rem;">
            <el-pagination style="width:300px;display: inline-block; margin-left: 2rem;" @size-change="handleSizeChange" @current-change="handleCurrentChange" :page-sizes="[10, 20, 50, 100]" :page-size="size" layout="total, sizes, prev, pager, next, jumper" :total="total"></el-pagination>
        </p>

    </el-row>
    <div class="infinite-list" style="overflow-y: auto;" :style="{height:(fullHeight-130)+'px'}" >
        <el-collapse>
            <template v-for="(item, i) in list" class="infinite-list-item">
                <el-collapse-item style="width:100%;" class="cx">
                    <template slot="title" style="width:90%;">
                        <el-row class="contentRow"  style="white-space:nowrap;width:100%; text-align: center;" :style="{background:'ERROR'==item.logLevel?'#fde2e2':i%2==0?'#eee':'#fff'}">
                            <el-col :span="1" class="hidden-md-and-down"><p><el-checkbox v-model="item.check"></el-checkbox></p></el-col>
                            <el-col :span="2" ><p>{{item.time}}</p></el-col>
                            <el-col :span="2"><p style="overflow: hidden;text-overflow:ellipsis;white-space: nowrap;"><el-link type="primary" @click="appName(item.appName)">{{item.appName}}</el-link></p></el-col>
                            <el-col :span="2"><p><el-link type="primary" @click="trace(item.traceId)">{{item.traceId}}</el-link></p></el-col>
                            <p style="overflow: hidden;text-overflow:ellipsis;white-space: nowrap;text-align: left; padding-left: 2rem;" v-html="lightCode(item.content,300)"></p>
                        </el-row>
                    </template>
                    <div style="padding:0 4rem; overflow-x:auto;overflow-y:hidden;">
                        <p v-text="'['+item.logLevel+'] '+'['+item.serverName+'] '+'['+item.firmId+'] '+item.className+'.'+item.method+':'+item.lineNumber"></p>
                        <p v-html="hightLightCode(item.content)"></p>
                    </div>
                </el-collapse-item>
            </template>
        </el-collapse>
    </div>


</div>
<script type="text/javascript">
    new Vue({
        el: '#app',
        data: function() {
            return {
                logmonitor:{
                    open:false,
                    myChart:null,
                    intervalID:null,
                },
                from:{
                    logLevel:""
                    ,traceId:""
                    ,appName:""
                    ,firmId:""
                },
                dateTimeRange:[new Date(new Date(new Date().toLocaleDateString()).getTime()), new Date(new Date(new Date().toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1)],
                searchKey:'',
                fullHeight: document.documentElement.clientHeight,
                list: [],
                sort:[{"dtTime":"desc"}],
                size:50,
                page:0,
                total:0,
                lock:false,
                isIndeterminate: true,
                checkAll: false,
                drawer: false,
                tableData:[],
                esIndex:'plume_log_run_',
                loading:null,
            }
        },methods:{
            lightCode(code, limit){
                if (!code){
                    return '';
                }
                code = code.replaceAll("<","&lt;")
                if (limit && code.length > limit){
                    code = code.substring(0,limit);
                }
                if(this.searchKey){
                    let re = new RegExp("(" + this.searchKey.replace(/\*/g,'') + ")", "gmi");
                    code = code.replace(re, '<em>$1</em>');
                }
                return '<div style="word-break:break-all">'+code+"</div>";
            },
            hightLightCode(code){
                if (!code){
                    return '';
                }
                code = code.replaceAll("<","&lt;")
                if(this.searchKey){
                    let re = new RegExp("(" + this.searchKey.replace(/\*/g,'') + ")", "gmi");
                    code = code.replace(re, '<em>$1</em>');
                }
                if(code.indexOf('java.')>-1){
                    return Prism.highlight(code, Prism.languages.stackjava, 'stackjava').replace(/\n/g,'<br/>').replace(/&lt;/g,'<').replace(/&gt;/g,'>')
                } else {
                    return code.replace(/\n/g,'<br/>');
                }
            },
            clearCheckBox() {
                //清空选择
                this.list.forEach(item => {
                    item.check = false;
                })
            },
            trace(traceId){
                this.from.traceId = traceId;
                this.onSubmit();
            },
            rzdj(firmId){
                this.from.firmId = firmId;
                this.onSubmit();
            },
            serverName(serverName){
                this.from.serverName = serverName;
                this.onSubmit();
            },
            appName(appName){
                this.from.appName = appName;
                this.onSubmit();
            },
            handleCurrentChange(page){
                this.page = page-1;
                this.list = [];
                this.get();
            },
            handleSizeChange(size){
                this.size = size;
                this.get();
            },
            onSubmit(){
                this.page = 0;
                this.get();
            },
            showMonitor(){
                this.logmonitor.open = true;
                this.get();
            },
            get(){
                var a = 0;
                try {
                    if (this.logmonitor.open){
                        a = this.execMonitor()
                    }else{
                        a = this.exec()
                    }
                } catch(err) {
                    this.$message.error("错误:"+err);
                } finally {
                    if(a != -1){
                        this.lock = false;
                    }
                }
            },
            exec(){
                if (this.loading){
                    console.log("调用中")
                    return;
                }
                this.loading = ELEMENT.Loading.service({ fullscreen: true });
                var  {filters,dateList} = this.getQueryStrFilter();
                let query = {"query":{"bool":{"must":filters}},"highlight": {"fields" : {"content" : {}}},"sort":this.sort,size:this.size,from:(this.page*this.size)};
                let $this = this;
                this.sysMethod({url:"/serverlog/query", method:'get', params:{url:dateList.join(','),queryStr:JSON.stringify(query)}}).then(function (response) {
                    $this.loading.close();
                    $this.loading = null
                    $this.list = [];
                    var res = JSON.parse(response.data);
                    if(res.hits && res.hits.total){
                        $this.total = res.hits.total.value;
                        res.hits.hits.forEach(v=>{
                            var it = v._source;
                            it.id = v._id;
                            it.time = $this.dateFormat('yyyy-MM-dd HH:mm:ss',new Date(it.dtTime));
                            $this.list.push(it);
                        })
                    }
                });
            },
            getQueryStrFilter(){
                if(this.lock || this.page * this.size > this.total){
                    return -1;
                }
                this.lock = true;
                if (!this.dateTimeRange || !this.dateTimeRange.length){
                    this.$message.error("请选择时间!");
                    return 0;
                }
                let filters = [];
                for(let itemKey in this.from) {
                    if(this.from[itemKey]){
                        filters.push({
                            "match_phrase_prefix":{
                                [itemKey]:this.from[itemKey]
                            }
                        })
                    }
                }
                if(this.searchKey){
                    filters.push({
                        "match_phrase_prefix":{
                            "content": this.searchKey
                        }
                    })
                }

                //列出范围内的日期
                let dateList=[];
                //判断日期
                if(this.dateTimeRange.length>0 && this.dateTimeRange[0]!=''){
                    let startDate=new Date(this.dateTimeRange[0]);
                    let endDate=new Date(this.dateTimeRange[1]);
                    filters.push({
                        "range":{
                            "dtTime":{
                                "gte": Date.parse(startDate),
                                "lte": Date.parse(endDate),
                            }
                        }
                    });
                    if(startDate){
                        while(startDate<=endDate){
                            dateList.push('plume_log_run_'+this.dateFormat('yyyyMMdd', startDate))
                            startDate = new Date(startDate.setDate(startDate.getDate()+1));
                        }
                    }
                }
                return  {filters,dateList};
            },
            getDateUnit(){
                let differenceMinutes=(new Date(this.dateTimeRange[1]).getTime()-new Date(this.dateTimeRange[0]).getTime())/60000;
                if (differenceMinutes/60/24>1){
                    return {interval:'1d',formate:'MM-dd'};
                }else if (differenceMinutes/60>10){
                    return {interval:'1h',formate:'HH'};
                }else if (differenceMinutes>60){
                    return {interval:'10m',formate:'HH:mm'};
                }else if (differenceMinutes>10){
                    return {interval:'1m',formate:'HH:mm'};
                }else{
                    return {interval:'10s',formate:'HH:mm:ss'};
                }
            },
            onClean(){
                let firmId = this.from.firmId;
                this.from = {logLevel:"",traceId:"",appName:"",firmId:firmId}
                this.searchKey="";
                this.dateTimeRange=[new Date(new Date(new Date().toLocaleDateString()).getTime()), new Date(new Date(new Date().toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1)]
                if (!this.logmonitor.open){
                    this.page = 0;
                    this.total = 0;
                }
                this.get();
            },
            dateFormat(fmt, date) {
                let ret;
                const opt = {
                    "y+": date.getFullYear().toString(),        // 年
                    "M+": (date.getMonth() + 1).toString(),     // 月
                    "d+": date.getDate().toString(),            // 日
                    "H+": date.getHours().toString(),           // 时
                    "m+": date.getMinutes().toString(),         // 分
                    "s+": date.getSeconds().toString()          // 秒
                    // 有其他格式化字符需求可以继续添加，必须转化成字符串
                };
                for (let k in opt) {
                    ret = new RegExp("(" + k + ")").exec(fmt);
                    if (ret) {
                        fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
                    };
                };
                return fmt;
            },
            toSql(){
                var statementStr = null;
                var parametersStr = null;
                for (var i =0; i<this.list.length; i++){
                    var item = this.list[i];
                    if (item.check){
                        if (parametersStr==null && item.content.indexOf("Parameters: ")!=-1){
                            parametersStr = item.content.substring(item.content.lastIndexOf('Parameters: ')+12);
                        } else if(statementStr==null && item.content.indexOf("Preparing: ")!=-1){
                            statementStr = item.content.substring(item.content.lastIndexOf('Preparing: ')+11)
                        }
                    }
                    if (statementStr!=null && parametersStr!=null){
                        break;
                    }
                }
                if (statementStr==null || parametersStr==null){
                    return;
                }
                var parametersStr = parametersStr.split(",");
                for(var i = 0; i < parametersStr.length; i++) {
                    // 如果数据中带括号将使用其他逻辑
                    tempStr = parametersStr[i].substring(0, parametersStr[i].indexOf("("));
                    // 获取括号中内容
                    typeStr = parametersStr[i].substring(parametersStr[i].indexOf("(")+1,parametersStr[i].indexOf(")"));
                    // 如果为字符类型
                    if (typeStr == "String" || typeStr == "Timestamp") {
                        statementStr = statementStr.replace("?", "'"+tempStr.trim()+"'");
                    }else{
                        // 数值类型
                        statementStr = statementStr.replace("?", tempStr.trim());
                    }
                }
                return statementStr;
            }
        },mounted(){
            var $vuethis = this;
            window.addEventListener("resize", () => $vuethis.fullHeight = document.documentElement.clientHeight);
            let traceId = LX.request("traceId")
            if (traceId){
                this.trace(traceId);
            }else{
                this.onSubmit();
            }
        }
    })

</script>
<style>
    body{
        overflow:scroll;
        overflow-x:hidden;
        overflow-y:hidden;
    }

    /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
    ::-webkit-scrollbar {
        width: 5px;  /*滚动条宽度*/
        height: 10px;  /*滚动条高度*/
    }

    /*定义滚动条轨道 内阴影+圆角*/
    ::-webkit-scrollbar-track {
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
        border-radius: 5px;  /*滚动条的背景区域的圆角*/
        background-color: #fff;/*滚动条的背景颜色*/
    }

    /*定义滑块 内阴影+圆角*/
    ::-webkit-scrollbar-thumb {
        border-radius: 2px;  /*滚动条的圆角*/
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
        background-color: #ddd;  /*滚动条的背景颜色*/
    }

    .contentRow:hover{
        background-color:#d9ecff!important
    }
    .contentRow p{
        margin: 0;
    }
    .el-collapse-item__arrow{
        display: none;
    }
    .cx em {
        background: #ff0;
    }


    .el-dialog {
        margin: 0 auto;
    }
    .el-dialog__body {
        padding:10px;
    }
    .el-dialog__header {
        display: none;
    }
    .dj-dialog-content {
        padding: 0;
        overflow: unset;
    }
</style>
</body>
</html>
